home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / SCC.C < prev    next >
C/C++ Source or Header  |  1993-11-21  |  54KB  |  1,433 lines

  1. /* Generic driver for Z8530 boards, modified from the PE1CHL
  2.  * driver for use with NOS. This version also supports the NRS
  3.  * mode when used as an asynch port. Device setup is similar to
  4.  * that of the PE1CHL version, with the addition of user specification
  5.  * of buffer size (bufsize). See the file "scc.txt" for general
  6.  * information on the use of this driver and setup procedures.
  7.  *
  8.  * General differences between this driver and the original version:
  9.  *
  10.  * 1) Slip encoding and decoding is not done in the driver, but
  11.  *    using the routines in slip.c, and these routines are supported
  12.  *    in a manner similar to the asynch routines for the 8250. The
  13.  *    input is handled via fifo buffer, while output is direct. The
  14.  *    routines scc_send and get_scc are called via pointers in the
  15.  *    Slip and Nrs structs for the parcticular channel.
  16.  *
  17.  * 2) The timer routine, scctim, is not installed directly in the
  18.  *    timer interrupt chain, but is called through the systick routine
  19.  *    in pc.c.
  20.  *
  21.  * 3) Facilities of nos are used whenever possible in place of direct
  22.  *    structure or variable manipulation. Mbuf management is handled
  23.  *    this way, along with interface initialization.
  24.  *
  25.  * 4) Nrs mode support is added in a manner similar to that of the
  26.  *    Slip support. I have not had an opportunity to test this, but
  27.  *    it is essentially identical to the way the 8250 version works.
  28.  *
  29.  * 5) Callsign specification on radio modes (kiss,nrs,ax25) is an
  30.  *    option. If not supplied, the value of Mycall will be used.
  31.  *
  32.  * 6) Bufsize specification is now a parameter on setup of each channel.
  33.  *    This is the size of the fifo on asynch input, and the size of
  34.  *    mbuf buffers for sdlc mode. Since the fifo buffer can fill up,
  35.  *    this value should be reasonably large for asynch mode. Mbufs
  36.  *    are chained when they fill up, so having a small bufsize with
  37.  *    sdlc modes (ax25) does not result in loss of characters.
  38.  *
  39.  * 7) Because slip and nrs decoding is handled outside the driver,
  40.  *    sccstat cannot be used to report sent and receive packet counts
  41.  *    in asynch mode, and these fields are blanked on display in asynch
  42.  *    modes.
  43.  *
  44.  *
  45.  * I am interested in setting up some default initializations for
  46.  * the popular Z8530 boards, to minimize user problems in constructing
  47.  * the proper attach init entries. These would allow for shortened
  48.  * entries to use the defaults, such as "attach scc 1 init drsi" to
  49.  * attach a DRSI board in standard configuration at its default address.
  50.  * Since I do not have complete technical information on all such boards,
  51.  * I would very much appreciate any information that users can provide
  52.  * me regarding particular boards.
  53.  *
  54.  * 1/25/90
  55.  *
  56.  * Modifications:
  57.  *
  58.  * 2/17/90:
  59.  *
  60.  * 1) Added mods from PE1CHL which reflect relevent changes to the
  61.  *    scc driver in his version of net between 10/89 and 1/90. Changes
  62.  *    incorporated include additional delays in sccvec.asm, addition
  63.  *    of external clock mode, and initialization for the 8536 as a
  64.  *    clock divider on the DRSI board. "INLINE" is a slight delay
  65.  *    for register access incorporated for use with the inline i/o
  66.  *    code in MSC. This may not be useful or necessary with TURBO.
  67.  *    Changes making "TPS" a variable were not added, since the
  68.  *    scc timer does not install itself on the hardware interrupt
  69.  *    in this version.
  70.  *
  71.  *
  72.  * Ken Mitchum, KY3B       km@cs.pitt.edu  km@dsl.pitt.edu
  73.  *                             or mail to the tcpip group
  74.  *
  75.  *
  76.  * 5/07/92:
  77.  *
  78.  * 1) Changes needed for BayCom-USCC card were made. CTS-Interrupt
  79.  *    was disabled, because it keeps the system hanging. Clock sources
  80.  *    will be changed when transmitter is switched on/off, if internal
  81.  *    clock is used. Now DF9IC's G3RUH compatible modem is supported,
  82.  *    which needs NRZ-signals and provides external clocks.
  83.  *
  84.  * René Stange, DG0FT @DB0KG.DEU.EU
  85.  *
  86.  */
  87.  
  88. /* Added ANSI-style prototypes, reformatted source, minor delinting.
  89.  * Integrated into standard 900201 NOS by KA9Q.
  90.  */
  91.  
  92. /*
  93.  * Generic driver for Z8530 SCC chip in SLIP, KISS or AX.25 mode.
  94.  *
  95.  * Written by R.E. Janssen (PE1CHL) using material from earlier
  96.  * EAGLE and PC100 drivers in this package.
  97.  *
  98.  * The driver has initially been written for my own Atari SCC interface
  99.  * board, but it could eventually replace the other SCC drivers.
  100.  *
  101.  * Unfortunately, there is little consistency between the different interface
  102.  * boards, as to the use of a clock source, the solution for the fullduplex
  103.  * clocking problem, and most important of all: the generation of the INTACK
  104.  * signal.    Most designs do not even support the generation of an INTACK and
  105.  * the read of the interrupt vector provided by the chip.
  106.  * This results in lots of configuration parameters, and a fuzzy
  107.  * polltable to be able to support multiple chips connected at one interrupt
  108.  * line...
  109.  *
  110.  */
  111.  
  112.  
  113. #include <stdlib.h>
  114. #include <stdio.h>
  115. #include <ctype.h>
  116. #include <time.h>
  117. #include <dos.h>
  118. #include "global.h"
  119. #include "config.h"
  120. #ifdef SCC
  121. #include "mbuf.h"
  122. #include "netuser.h"
  123. #include "proc.h"
  124. #include "iface.h"
  125. #include "pktdrvr.h"
  126. #include "slip.h"
  127. #ifdef NRS
  128. #include "nrs.h"
  129. #endif
  130. #include "n8250.h"
  131. #include "scc.h"
  132. #include "n8530.h"
  133. #include "n8536.h"
  134. #include "ax25.h"
  135. #include "trace.h"
  136. #include "pc.h"
  137. #include "kiss.h"
  138. #include "devparam.h"
  139.  
  140. /* interrupt handlers */
  141. extern INTERRUPT sccvec();
  142. extern INTERRUPT sccnovec();
  143.  
  144. /* variables used by the SCC interrupt handler in sccvec.asm */
  145. static INTERRUPT (*Orgivec)();          /* original interrupt vector */
  146.  
  147. struct sccinfo Sccinfo = {0};           /* global info about SCCs */
  148. struct sccchan *Sccchan[2 * MAXSCC] = {0}; /* information per channel */
  149. ioaddr Sccvecloc = {0};                 /* location to access for SCC vector */
  150. unsigned char Sccmaxvec = {0};          /* maximum legal vector from SCC */
  151. ioaddr Sccpolltab[MAXSCC+1][2] = {0};    /* polling table when no vectoring */
  152.  
  153. #if defined(INLINE)
  154. static unsigned scc_delay(unsigned v)   /* delay for about 5 PCLK cycles */
  155.                                         /* pass-through used for input */
  156. {
  157.    int i,j;                             /* it takes time to save them */
  158.    return v;                            /* return the passed parameter */
  159. }
  160. #endif
  161.  
  162. static unsigned char Random = 0;            /* random number for p-persist */
  163. static int hsize = sizeof(struct phdr);     /* size of the pseudo-header */
  164.  
  165. #define z 0
  166.  
  167. static int scc_raw __ARGS((struct iface *ifp,struct mbuf *bp));
  168. static int scc_stop __ARGS((struct iface *ifp,int tmp));
  169. static int scc_send __ARGS((int dev,struct mbuf *bp));
  170.  
  171. static int32 scc_aioctl __ARGS((struct iface *ifp,int cmd,int set,int32 val));
  172. static int32 scc_sioctl __ARGS((struct iface *ifp,int cmd,int set,int32 val));
  173.  
  174. /* set SCC channel speed
  175.  * clkmode specifies the division rate (1,16,32) inside the SCC
  176.  * returns the selected brgrate for "real speed" calculation
  177.  */
  178. static unsigned int
  179. scc_speed(struct sccchan *scc,unsigned int clkmode,long speed)
  180. {
  181.     long spdclkm = speed * clkmode;
  182.  
  183.     /* calculate baudrate generator value */
  184.     if(spdclkm == 0) {
  185.         return 65000U;        /* avoid divide-by-zero */
  186.     } else {
  187.         unsigned int brgrate = (unsigned)((Sccinfo.clk + spdclkm) / (spdclkm * 2)) - 2;
  188.  
  189.         DISABLE();
  190.  
  191.         cl(scc,R14,BRENABL);        /* disable baudrate generator */
  192.         wr(scc,R12,brgrate);        /* brg rate LOW */
  193.         wr(scc,R13,brgrate >> 8);        /* brg rate HIGH */
  194.         or(scc,R14,BRENABL);        /* enable baudrate generator */
  195.  
  196.         RESTORE();
  197.         return brgrate;
  198.     }
  199. }
  200.  
  201. /* Switch the SCC to "receive" mode (or: switch off transmitter)
  202.  * Only to be called from an interrupt handler, while in AX.25 mode */
  203. static void
  204. scc_txoff(struct sccchan *scc)
  205. {
  206.     cl(scc,R5,RTS);                             /* turn off RTS line */
  207.  
  208.     if(Sccinfo.hwtype & HWPRIMUS) {             /* PRIMUS has another PTT bit... */
  209.         WRREG(scc->ctrl + 4,Sccinfo.hwparam);   /* clear that bit! */
  210.     }
  211.     if(!scc->fulldup && !scc->extclock) {       /* no fulldup divider? */
  212.         cl(scc,R5,TxENAB);                      /* then disable the transmitter */
  213.         scc_speed(scc,32,scc->speed);           /* back to receiver baudrate */
  214.         /* DPLL -> Rx clk, DPLL -> Tx CLK, RxCLK -> TRxC pin */
  215.         wr(scc,R11,RCDPLL|TCDPLL|TRxCOI|TRxCDP);
  216.         or(scc,R3,ENT_HM|RxENABLE);             /* enable the receiver, hunt mode */
  217.     }
  218. }
  219.  
  220. /* Throw away receive mbuf(s) when an error occurred */
  221. static void
  222. scc_tossb (struct sccchan *scc)
  223. {
  224.     struct mbuf *bp = scc->rbp;
  225.  
  226.     if(bp != NULLBUF) {
  227.         free_p(bp->next);
  228.         free_p(bp->dup);                    /* Should be NULLBUF */
  229.         bp->next = NULLBUF;
  230.         scc->rbp1 = bp;                     /* Don't throw this one away */
  231.         bp->cnt = hsize;                    /* Simply rewind it */
  232.     } 
  233. }
  234.  
  235. /* Blocking read from asynch input.
  236.  * Essentially the same as get_asy() in 8250.c
  237.  * See comments in asy_rxint().
  238.  */
  239. static int
  240. get_scc(int dev)
  241. {
  242.     int c;
  243.     struct fifo *fp = &Sccchan[dev]->fifo;
  244.  
  245.     DISABLE();
  246.  
  247.     while(fp->cnt == 0) {
  248.         if(pwait(fp) != 0) {
  249.             RESTORE();
  250.             return -1;
  251.         }
  252.     }
  253.     fp->cnt--;
  254.  
  255.     RESTORE();
  256.  
  257.     c = *fp->rp++;
  258.  
  259.     if(fp->rp >= &fp->buf[fp->bufsize]) {
  260.         fp->rp = fp->buf;
  261.     }
  262.     return c;
  263. }
  264.  
  265. /* --START--------- Interrupt handlers for sdlc mode (AX.25) --------START-- */
  266. /* Transmitter interrupt handler */
  267. static void
  268. scc_sdlctx(struct sccchan *scc)
  269. {
  270.     struct mbuf *bp;
  271.  
  272.     scc->txints++;
  273.  
  274.     switch(scc->a.tstate) {                     /* look at transmitter state */
  275.     case ACTIVE:                                /* busy sending data bytes */
  276.         bp = scc->tbp;
  277.         while(bp->cnt == 0) {                     /* nothing left in this mbuf? */
  278.             bp = bp->next;                      /* save link to next */
  279.             free_mbuf(scc->tbp);                /*KM*/
  280.             if((scc->tbp = bp) == NULLBUF) {    /* see if more mbufs follow */
  281.                 if(RDREG(scc->ctrl) & TxEOM) {  /* check tx underrun status */
  282.                     scc->rovers++;              /* oops, an underrun! count them */
  283.                     WRREG(scc->ctrl,SEND_ABORT);    /* send an abort to be sure */
  284.                     scc->a.tstate = TAIL;       /* key down tx after TAILTIME */
  285.                     scc->timercount = scc->a.tailtime;
  286.                     return;
  287.                 }
  288.                 cl(scc,R10,ABUNDER);            /* frame complete, allow CRC transmit */
  289.                 scc->a.tstate = FLUSH;
  290.                 WRREG(scc->ctrl,RES_Tx_P);      /* reset pending int */
  291.                 return;
  292.             }
  293.         }
  294.         /* now bp = scc->tbp (either from while or from if stmt above) */
  295.         WRREG(scc->data,*(bp->data++));         /* send the character */
  296.         bp->cnt--;                              /* decrease mbuf byte count */
  297.         return;
  298.     case FLUSH:                                 /* CRC just went out, more to send? */
  299.         or(scc,R10,ABUNDER);                    /* re-install underrun protection */
  300.         /* verify that we are not exeeding max tx time (if defined) */
  301.         if((scc->timercount != 0
  302.           || scc->a.maxkeyup == 0)
  303.           &&(scc->tbp = scc->sndq) != NULLBUF) {    /* dequeue a frame */
  304.             scc->sndq = scc->sndq->anext;
  305.             WRREG(scc->ctrl,RES_Tx_CRC);        /* reset the TX CRC generator */
  306.             scc->a.tstate = ACTIVE;
  307.             scc_sdlctx(scc);                    /* write 1st byte */
  308.             WRREG(scc->ctrl,RES_EOM_L);         /* reset the EOM latch */
  309.             return;
  310.         }
  311.         scc->a.tstate = TAIL;                   /* no more, key down tx after TAILTIME */
  312.         scc->timercount = scc->a.tailtime;
  313. #ifdef XXX
  314.         WRREG(scc->ctrl,RES_Tx_P);
  315.         return;
  316. #endif        
  317.     default:                                    /* another state */
  318.         WRREG(scc->ctrl,RES_Tx_P);              /* then don't send anything */
  319.         return;
  320.     }
  321. }
  322.  
  323. /* External/Status interrupt handler */
  324. static void
  325. scc_sdlcex(struct sccchan *scc)
  326. {
  327.     unsigned char status = RDREG(scc->ctrl);
  328.     unsigned char changes = status ^ scc->status;
  329.  
  330.     scc->exints++;
  331.  
  332.     if(changes & BRK_ABRT) {                    /* Received an ABORT */
  333.         if(status & BRK_ABRT) {                 /* is this the beginning? */
  334.             if(scc->rbp != NULLBUF) {           /* did we receive something? */
  335.                 /* check if a significant amount of data came in */
  336.                 /* this is because the drop of DCD tends to generate an ABORT */
  337.                 if(scc->rbp->next != NULLBUF || scc->rbp->cnt > hsize) {
  338.                     scc->rxerrs++;              /* then count it as an error */
  339.                 }
  340.                 scc_tossb(scc);                 /* throw away buffer */
  341.             }
  342.             VOID(RDREG(scc->data));             /* flush the FIFO */
  343.             VOID(RDREG(scc->data));
  344.             VOID(RDREG(scc->data));
  345.         }
  346.     }
  347.     if(changes & CTS) {                         /* CTS input changed state */
  348.         if(status & CTS) {                      /* CTS is now ON */
  349.             if(scc->a.tstate == KEYWT && scc->a.txdelay == 0) {     /* zero TXDELAY = wait for CTS */
  350.                 scc->timercount = 1;            /* it will start within 10 ms */
  351.             }
  352.         }
  353.     }
  354.     if(changes & DCD) {                         /* DCD input changed state */
  355.         if(status & DCD) {                      /* DCD is now ON */
  356.             if(!scc->extclock) {
  357.                 WRSCC(scc->ctrl,R14,SEARCH|scc->wreg[R14]); /* DPLL: enter search mode */
  358.             }
  359.             or(scc,R3,ENT_HM|RxENABLE);         /* enable the receiver, hunt mode */
  360.         } else {                                /* DCD is now OFF */
  361.             cl(scc,R3,ENT_HM|RxENABLE);         /* disable the receiver */
  362.             VOID(RDREG(scc->data));             /* flush the FIFO */
  363.             VOID(RDREG(scc->data));
  364.             VOID(RDREG(scc->data));
  365.             if(scc->rbp != NULLBUF) {           /* did we receive something? */
  366.                 /* check if a significant amount of data came in */
  367.                 /* this is because some characters precede the drop of DCD */
  368.                 if(scc->rbp->next != NULLBUF || scc->rbp->cnt > hsize) {
  369.                     scc->rxerrs++;              /* then count it as an error */
  370.                 }
  371.                 scc_tossb(scc);                 /* throw away buffer */
  372.             }
  373.         }
  374.     }
  375.     scc->status = status;
  376.     WRREG(scc->ctrl,RES_EXT_INT);
  377. }
  378.  
  379. /* Receiver interrupt handler */
  380. static void
  381. scc_sdlcrx(struct sccchan *scc)
  382.     struct mbuf *bp = scc->rbp1;
  383.     
  384.     if(bp == NULLBUF) {                 /* no buffer available now */
  385.         if(scc->rbp == NULLBUF) {
  386.             bp = scc->rbp = scc->rbp1 = alloc_mbuf(scc->bufsiz + hsize);
  387.             bp->cnt = hsize;
  388.         } else {
  389.             for(bp = scc->rbp; bp->next != NULLBUF; bp = bp->next) ;
  390.             bp = bp->next = scc->rbp1 = alloc_mbuf(scc->bufsiz);
  391.         }
  392.         if(bp == NULLBUF) {
  393.             VOID(RDREG(scc->data));     /* so we have to discard the char */
  394.             or(scc,R3,ENT_HM);          /* enter hunt mode for next flag */
  395.             scc_tossb(scc);             /* put buffers back on pool */
  396.             scc->nospace++;             /* count these events */
  397.             return;
  398.         }
  399.     }
  400.     /* now, we have a buffer (at bp). read character and store it */
  401.     bp->data[bp->cnt++] = RDREG(scc->data);
  402.  
  403.     if(bp->cnt == bp->size) {           /* buffer full? */
  404.         scc->rbp1 = NULLBUF;            /* acquire a new one next time */
  405.     }
  406.     scc->rxints++;
  407. }
  408.  
  409. /* Receive Special Condition interrupt handler */
  410. static void
  411. scc_sdlcsp(struct sccchan *scc)
  412. {
  413.     struct mbuf *bp;
  414.     struct phdr *ph;
  415.  
  416.     unsigned char status = rd(scc,R1);          /* read receiver status */
  417.  
  418.     scc->spints++;
  419.     VOID(RDREG(scc->data));                     /* flush offending character */
  420.  
  421.     if(status & Rx_OVR) {                       /* receiver overrun */ 
  422.         scc->rovers++;                          /* count them */ 
  423.         or(scc,R3,ENT_HM);                      /* enter hunt mode for next flag */ 
  424.         scc_tossb(scc);                         /* rewind the buffer and toss */ 
  425.     } 
  426.     if(status & END_FR                          /* end of frame */ 
  427.       && scc->rbp != NULLBUF) {                 /* at least received something */ 
  428.         if((status & CRC_ERR) == 0              /* no CRC error is indicated */ 
  429.           && (status & 0xe) == RES8             /* 8 bits in last byte */ 
  430.           && scc->rbp->cnt > hsize) {           
  431.             /* we seem to have a good frame. but the last byte received */ 
  432.             /* from rx interrupt is in fact a CRC byte, so discard it */ 
  433.             if(scc->rbp1 != NULLBUF) { 
  434.                 scc->rbp1->cnt--;               /* current mbuf was not full */ 
  435.             } else { 
  436.                 /* find last mbuf */ 
  437.                 for(bp = scc->rbp; bp->next != NULLBUF; bp = bp->next) ;
  438.                 bp->cnt--;                      /* last byte is first CRC byte */ 
  439.             } 
  440.             ph = (struct phdr *)scc->rbp->data; 
  441.             ph->iface = scc->iface; 
  442.             ph->type = CL_AX25; 
  443.             enqueue(&Hopper,scc->rbp); 
  444.             scc->rbp = scc->rbp1 = NULLBUF;
  445.             scc->rxframes++; 
  446.         } else {                                /* a bad frame */ 
  447.             scc_tossb(scc);                     /* throw away frame */
  448.             scc->rxerrs++; 
  449.         } 
  450.     } 
  451.     WRREG(scc->ctrl,ERR_RES); 
  452. }
  453. /* ---END--------- Interrupt handlers for sdlc mode (AX.25) ----------END-- */
  454.  
  455.  
  456. /* --START- Interrupt handlers for asynchronous modes (kiss, slip) -START-- */
  457. /* Transmitter interrupt handler */
  458. /* This routine sends data from mbufs in SLIP format */
  459. static void
  460. scc_asytx(struct sccchan *scc)
  461. {
  462.     struct mbuf *bp;
  463.  
  464.     scc->txints++;
  465.  
  466.     if(scc->txchar != 0) {              /* a character pending for transmit? */
  467.         WRREG(scc->data,scc->txchar);   /* send it now */
  468.         scc->txchar = 0;                /* next time, ignore it */
  469.         return;
  470.     }
  471.     if(scc->tbp == NULLBUF) {           /* nothing to send? */
  472.         if((scc->tbp = scc->sndq) != NULLBUF) {     /* dequeue next frame */
  473.             scc->sndq = scc->sndq->anext;
  474.             WRREG(scc->data,FR_END);    /* send FR_END to flush line garbage */
  475.         } else {
  476.             WRREG(scc->ctrl,RES_Tx_P);  /* else only reset pending int */
  477.         }
  478.         return;
  479.     }
  480.     bp = scc->tbp;
  481.  
  482.     while(bp->cnt == 0) {                  /* nothing left in this mbuf? */
  483.         bp = bp->next;                  /* save link to next */
  484.         free_mbuf(scc->tbp);
  485.  
  486.         if((scc->tbp = bp) == NULLBUF){ /* see if more mbufs follow */
  487.             WRREG(scc->data,FR_END);    /* frame complete, send FR_END */
  488.             return;
  489.         }
  490.     }
  491.     /* now bp = scc->tbp (either from while or from if stmt above) */
  492.  
  493.     WRREG(scc->data,*(bp->data));       /* just send the character */
  494.     bp->cnt--;                          /* decrease mbuf byte count */
  495.     bp->data++;                         /* and increment the data pointer */
  496. }
  497.  
  498. /* External/Status interrupt handler */
  499. static void
  500. scc_asyex(struct sccchan *scc)
  501. {
  502.     unsigned char status = RDREG(scc->ctrl);
  503.     unsigned char changes = status ^ scc->status;
  504.  
  505.     scc->exints++;
  506.  
  507.     if(changes & BRK_ABRT) {            /* BREAK? */
  508.         if((status & BRK_ABRT) == 0)    /* BREAK now over? */
  509.             VOID(RDREG(scc->data));     /* read the NUL character */
  510.     }
  511.     scc->status = status;
  512.     WRREG(scc->ctrl,RES_EXT_INT);
  513. }
  514.  
  515. /* Receiver interrupt handler under NOS.
  516.  * Since the higher serial protocol routines are all written to work
  517.  * well with the routines in 8250.c, it makes sense to handle
  518.  * asynch i/o with the 8530 in a similar manner. Therefore, these
  519.  * routines are as close to their counterparts in 8250.c as possible.
  520.  */
  521. static void
  522. scc_asyrx(struct sccchan *scc)
  523. {
  524.     struct fifo *fp = &(scc->fifo);
  525.  
  526.     scc->rxints++;
  527.  
  528.     do {
  529.         char c = RDREG(scc->data);
  530.         if(fp->cnt != fp->bufsize){
  531.             *fp->wp++ = c;
  532.             if(fp->wp >= &fp->buf[fp->bufsize])
  533.                 fp->wp = fp->buf;
  534.             fp->cnt++;
  535.         } else
  536.             scc->nospace++;
  537.     } while(RDREG(scc->ctrl) & Rx_CH_AV);
  538.     
  539.     psignal(fp,1);              /* eventually move this to timer routine */
  540. }
  541.  
  542. /* Receive Special Condition interrupt handler */
  543. static void
  544. scc_asysp(struct sccchan *scc)
  545. {
  546.     unsigned char status = rd(scc,R1);      /* read receiver status */
  547.  
  548.     scc->spints++;
  549.  
  550.     VOID(RDREG(scc->data));                 /* flush offending character */
  551.  
  552.     if(status & (CRC_ERR | Rx_OVR)) {       /* did a framing error or overrun occur ? */
  553.         scc->rovers++;                      /* report as overrun */
  554.     }
  555.     WRREG(scc->ctrl,ERR_RES);
  556. }
  557. /* ---END-- Interrupt handlers for asynchronous modes (kiss, slip) ---END-- */
  558.  
  559. /* initialize an SCC channel in SDLC mode */
  560. static void near
  561. scc_sdlc(struct sccchan *scc)
  562. {
  563.     scc->int_transmit = scc_sdlctx;         /* set interrupt handlers */
  564.     scc->int_extstat = scc_sdlcex;
  565.     scc->int_receive = scc_sdlcrx;
  566.     scc->int_special = scc_sdlcsp;
  567.  
  568.     DISABLE();
  569.  
  570.     wr(scc,R4,X1CLK|SDLC);                  /* *1 clock, SDLC mode */
  571.     wr(scc,R1,z);                           /* no W/REQ operation */
  572.     wr(scc,R3,Rx8|RxCRC_ENAB);              /* RX 8 bits/char, CRC, disabled */
  573.     wr(scc,R5,Tx8|DTR|TxCRC_ENAB);          /* TX 8 bits/char, disabled, DTR */
  574.     wr(scc,R6,z);                           /* SDLC address zero (not used) */
  575.     wr(scc,R7,FLAG);                        /* SDLC flag value */
  576.     wr(scc,R9,VIS);                         /* vector includes status */
  577.  
  578.     if(scc->extclock) {                     /* when using external clocks */
  579.         if(Sccinfo.hwtype & HWBAYCOM) {     /* DF9IC-modem? */
  580.             wr(scc,R10,CRCPS|NRZ|ABUNDER);    /* CRC preset 1, select NRZ, ABORT on underrun */
  581.             wr(scc,R11,RCTRxCP|TCRTxCP);    /* RXclk TRxC, TXclk RTxC. */
  582.         } else {
  583.             wr(scc,R10,CRCPS|NRZI|ABUNDER);    /* CRC preset 1, select NRZI, ABORT on underrun */
  584.             wr(scc,R11,RCRTxCP|TCTRxCP);    /* RXclk RTxC, TXclk TRxC. */
  585.         }
  586.         wr(scc,R14,z);                      /* No BRG options */
  587.         WRSCC(scc->ctrl,R14,DISDPLL|scc->wreg[R14]);    /* No DPLL operation */
  588.     } else {
  589.         wr(scc,R10,CRCPS|NRZI|ABUNDER);     /* CRC preset 1, select NRZI, ABORT on underrun */
  590.  
  591.         if(scc->fulldup) {                   /* when external clock divider */
  592.             if(Sccinfo.pclk) {               /* when using PCLK as clock source */
  593.                 if (Sccinfo.hwtype & HWBAYCOM) {
  594.                     /* RXclk DPLL, TXclk RTxC, out=DPLL (Echo duplex) */
  595.                     wr(scc,R11,RCDPLL|TCRTxCP|TRxCOI|TRxCDP);
  596.                 } else {
  597.                     /* RXclk DPLL, TXclk RTxC, out=BRG. external /32 TRxC->RTxC */
  598.                     wr(scc,R11,RCDPLL|TCRTxCP|TRxCOI|TRxCBR);
  599.                 }
  600.             } else {
  601.                 /* RXclk DPLL, TXclk TRxC.    external TX clock to TRxC */
  602.                 wr(scc,R11,RCDPLL|TCTRxCP);
  603.             }
  604.         } else {                            /* only half-duplex operation */
  605.             /* RXclk DPLL, TXclk BRG. BRG reprogrammed at every TX/RX switch */
  606. #ifdef    notdef                                /* KA9Q - for PSK modem */
  607.             wr(scc,R11,RCDPLL|TCBR);
  608. #else
  609.             /* DPLL -> Rx clk, (DPLL -> Tx CLK), DPLL -> TRxC pin */
  610.             wr(scc,R11,RCDPLL|TCDPLL|TRxCOI|TRxCDP);
  611. #endif
  612.         }
  613.         wr(scc,R14,Sccinfo.pclk? BRSRC:z);       /* BRG source = PCLK/RTxC */
  614.         WRSCC(scc->ctrl,R14,SSBR|scc->wreg[R14]);  /* DPLL source = BRG */
  615.         WRSCC(scc->ctrl,R14,SNRZI|scc->wreg[R14]); /* DPLL NRZI mode */
  616.     }
  617.     if (Sccinfo.hwtype & HWBAYCOM) {         /* BayCom-USCC card? */
  618.         wr(scc,R15,BRKIE|DCDIE);            /* enable ABORT, DCD interrupts */
  619.     } else {
  620.         wr(scc,R15,BRKIE|CTSIE|DCDIE);      /* enable ABORT, CTS & DCD interrupts */
  621.     }
  622.     if(RDREG(scc->ctrl) & DCD) {            /* DCD is now ON */
  623.         if (!scc->extclock) {
  624.             WRSCC(scc->ctrl,R14,SEARCH|scc->wreg[R14]); /* DPLL: enter search mode */
  625.         }
  626.         or(scc,R3,ENT_HM|RxENABLE);            /* enable the receiver, hunt mode */
  627.     }
  628.     WRREG(scc->ctrl,RES_EXT_INT);            /* reset ext/status interrupts */
  629.     WRREG(scc->ctrl,RES_EXT_INT);            /* must be done twice */
  630.     scc->status = RDREG(scc->ctrl);            /* read initial status */
  631.  
  632.     or(scc,R1,INT_ALL_Rx|TxINT_ENAB|EXT_INT_ENAB); /* enable interrupts */
  633.     or(scc,R9,MIE);                            /* master interrupt enable */
  634.  
  635.     RESTORE();
  636. }
  637.  
  638. /* initialize an SCC channel in asynchronous mode */
  639. static int near
  640. scc_async(struct sccchan *scc)
  641. {
  642.     struct fifo *fp = &(scc->fifo);
  643.  
  644.     fp->buf = mxallocw(scc->bufsiz);
  645.     fp->bufsize = scc->bufsiz;
  646.     fp->wp = fp->rp = fp->buf;
  647.  
  648.     scc->int_transmit = scc_asytx;      /* set interrupt handlers */
  649.     scc->int_extstat = scc_asyex;
  650.     scc->int_receive = scc_asyrx;
  651.     scc->int_special = scc_asysp;
  652.  
  653.     DISABLE();
  654.  
  655.     wr(scc,R4,X16CLK|SB1);              /* *16 clock, 1 stopbit, no parity */
  656.     wr(scc,R1,z);                       /* no W/REQ operation */
  657.     wr(scc,R3,Rx8);                     /* RX 8 bits/char, disabled */
  658.     wr(scc,R5,Tx8|DTR|RTS);             /* TX 8 bits/char, disabled, DTR RTS */
  659.     wr(scc,R9,VIS);                     /* vector includes status */
  660.     wr(scc,R10,NRZ|z);                  /* select NRZ */
  661.     wr(scc,R11,RCBR|TCBR);              /* clocks are BR generator */
  662.     wr(scc,R14,Sccinfo.pclk? BRSRC:z);  /* brg source = PCLK/RTxC */
  663.     wr(scc,R15,BRKIE);                  /* enable BREAK ext/status int */
  664.  
  665.     or(scc,R3,RxENABLE);                /* enable receiver */
  666.     or(scc,R5,TxENAB);                  /* enable transmitter */
  667.  
  668.     WRREG(scc->ctrl,RES_EXT_INT);       /* reset ext/status interrupts */
  669.     WRREG(scc->ctrl,RES_EXT_INT);       /* must be done twice */
  670.     scc->status = RDREG(scc->ctrl);     /* read initial status */
  671.  
  672.     or(scc,R1,INT_ALL_Rx|TxINT_ENAB|EXT_INT_ENAB);  /* enable interrupts */
  673.     or(scc,R9,MIE);                     /* master interrupt enable */
  674.  
  675.     RESTORE();
  676.     return 0;
  677. }
  678.  
  679. /* SCC driver initialisation. called on "attach scc <num> init ..." */
  680. static int
  681. scc_init(int nchips,ioaddr iobase,int space,int aoff,int boff,int doff,ioaddr intack,int ivec,int32 clk,int pclk,int hwtype,int hwparam)
  682. {
  683.     int chip, chan, d, dum = 1;
  684.  
  685.     Sccinfo.init = 1;
  686.     Sccinfo.nchips = nchips;
  687.     Sccinfo.maxchan = (2 * nchips) - 1;
  688.     Sccinfo.iobase = iobase;
  689.     Sccinfo.space = space;
  690.     Sccinfo.off[0] = aoff;
  691.     Sccinfo.off[1] = boff;
  692.     Sccinfo.doff = doff;
  693.     Sccinfo.ivec = ivec;
  694.     Sccinfo.clk = clk;
  695.     Sccinfo.pclk = pclk;
  696.     Sccinfo.hwtype = hwtype;
  697.     Sccinfo.hwparam = hwparam;
  698.  
  699.     /* reset and pre-init all chips in the system */
  700.     for(chip = 0; chip < nchips; chip++) {
  701.         ioaddr chipbase = iobase + chip * space;
  702.         ioaddr ctrl = chipbase + Sccinfo.off[0];
  703.  
  704.         DISABLE();                              /* because of 2-step accesses */
  705.         
  706.         VOID(RDREG(ctrl));                      /* make sure pointer is written */
  707.         WRSCC(ctrl,R9,FHWRES);                  /* force hardware reset */
  708.         for (d = 0; d < 1000; d++) {            /* wait a while to be sure */
  709.             dum *= 10;
  710.         }
  711.         for(chan = 0; chan < 2; chan++) {
  712.             ctrl = chipbase + Sccinfo.off[chan];
  713.  
  714.             /* initialize a single channel to no-op */
  715.             VOID(RDREG(ctrl));                  /* make sure pointer is written */
  716.             WRSCC(ctrl,R4,z);                   /* no mode selected yet */
  717.             WRSCC(ctrl,R1,z);                   /* no W/REQ operation */
  718.             WRSCC(ctrl,R2,16 * chip);           /* chip# in upper 4 bits of vector */
  719.             WRSCC(ctrl,R3,z);                   /* disable rx */
  720.             WRSCC(ctrl,R5,z);                   /* disable tx */
  721.             WRSCC(ctrl,R9,VIS);                 /* vector includes status, MIE off */
  722.             Sccpolltab[chip][chan] = ctrl;      /* store ctrl addr for polling */
  723.         }
  724.         if(hwtype & HWEAGLE) {                  /* this is an EAGLE card */
  725.             WRREG(chipbase + 4,0x08);           /* enable interrupt on the board */
  726.         }
  727.         if(hwtype & HWPC100) {                  /* this is a PC100 card */
  728.             WRREG(chipbase,hwparam);            /* set the MODEM mode (22H normally) */
  729.         }
  730.         if(hwtype & HWPRIMUS) {                 /* this is a PRIMUS-PC */
  731.             WRREG(chipbase + 4,hwparam);        /* set the MODEM mode (02H normally) */
  732.         }
  733.         if(hwtype & HWDRSI) {                   /* this is a DRSI PC*Packet card */
  734.             ioaddr z8536 = chipbase + 7;        /* point to 8536 master ctrl reg */
  735.  
  736.             /* Initialize 8536 to perform its divide-by-32 function */
  737.             /* This part copied from N6TTO DRSI-driver */
  738.  
  739.             /* Start by forcing chip into known state */
  740.             VOID(RDREG(z8536));                 /* make sure pointer is written */
  741.             WRSCC(z8536,CIO_MICR,0x01);         /* force hardware reset */
  742.  
  743.             for (d = 0; d < 1000; d++) {        /* wait a while to be sure */
  744.                 dum *= 10;
  745.             }
  746.             WRSCC(z8536,CIO_MICR,0x00);         /* Clear reset and start */
  747.  
  748.             /* Wait for chip to come ready */
  749.             while (RDSCC(z8536,CIO_MICR) != 0x02) {
  750.                 dum *= 10;
  751.             }
  752.             WRSCC(z8536,CIO_MICR,0x26);         /* NV|CT_VIS|RJA */
  753.             WRSCC(z8536,CIO_MCCR,0xf4);         /* PBE|CT1E|CT2E|CT3E|PAE */
  754.  
  755.             WRSCC(z8536,CIO_CTMS1,0xe2);        /* Continuous, EOE, ECE, Pulse output */
  756.             WRSCC(z8536,CIO_CTMS2,0xe2);        /* Continuous, EOE, ECE, Pulse output */
  757.  
  758.             WRSCC(z8536,CIO_CT1MSB,0x00);       /* Load time constant CTC #1 */
  759.             WRSCC(z8536,CIO_CT1LSB,0x10);
  760.             WRSCC(z8536,CIO_CT2MSB,0x00);       /* Load time constant CTC #2 */
  761.             WRSCC(z8536,CIO_CT2LSB,0x10);
  762.  
  763.             WRSCC(z8536,CIO_IVR,0x06);
  764.  
  765.             /* Set port direction bits in port A and B           */
  766.             /* Data is input on bits d1 and d5, output on d0 and d4. */
  767.             /* The direction is set by 1 for input and 0 for output  */
  768.  
  769.             WRSCC(z8536,CIO_PDCA,0x22);
  770.             WRSCC(z8536,CIO_PDCB,0x22);
  771.  
  772.             WRSCC(z8536,CIO_CSR1,CIO_GCB|CIO_TCB); /* Start CTC #1 running */
  773.             WRSCC(z8536,CIO_CSR2,CIO_GCB|CIO_TCB); /* Start CTC #2 running */
  774.             }
  775.  
  776.             RESTORE();
  777.     }
  778.     Sccpolltab[chip][0] = 0;                    /* terminate the polling table */
  779.     Sccvecloc = intack;                         /* location of INTACK/vector read */
  780.     Sccmaxvec = 16 * nchips;                    /* upper limit on valid vector */
  781.     Orgivec = getirq(ivec);                     /* save original interrupt vector */
  782.  
  783.     if(intack) {                                /* INTACK method selected? */
  784.         /* set interrupt vector to INTACK-generating routine  */
  785.         setirq(ivec,sccvec);
  786.     } else {
  787.         /* set interrupt vector to polling routine */
  788.         setirq(ivec,sccnovec);
  789.     }
  790.     /* enable the interrupt  */
  791.     maskon(ivec);
  792.     return 0;
  793. }
  794.  
  795.  
  796. /* Attach an SCC channel to the system, or initialize SCC driver.
  797.  * operation depends on argv[2]:
  798.  * when "init", the SCC driver is initialized, and global information about
  799.  * the hardware is set up.
  800.  * argv[0]: hardware type, must be "scc"
  801.  * argv[1]: number of SCC chips we will support
  802.  * argv[2]: mode, must be: "init" in this case
  803.  * argv[3]: base address of SCC chip #0 (hex)
  804.  * argv[4]: spacing between SCC chip base addresses
  805.  * argv[5]: offset from chip base address to channel A control register
  806.  * argv[6]: offset from chip base address to channel B control register
  807.  * argv[7]: offset from each channel's control register to data register
  808.  * argv[8]: address of INTACK/Read Vector port. 0 to read from RR3A/RR2B
  809.  * argv[9]: CPU interrupt vector number for all connected SCCs
  810.  * argv[10]: clock frequency (PCLK/RTxC) of all SCCs in cycles per second
  811.  *         prefix with "p" for PCLK, "r" for RTxC clock (for baudrate gen)
  812.  * argv[11]: optional hardware type (for special features)
  813.  * argv[12]: optional extra parameter for special hardware
  814.  *
  815.  * otherwise, a single channel is attached using the specified parameters:
  816.  * argv[0]: hardware type, must be "scc"
  817.  * argv[1]: SCC channel number to attach, 0/1 for first chip A/B, 2/3 for 2nd...
  818.  * argv[2]: mode, can be: "slip", "kiss", "ax25"
  819.  * argv[3]: interface label, e.g., "sl0"
  820.  * argv[4]: maximum transmission unit, bytes
  821.  * argv[5]: interface speed, e.g, "1200". prefix with "d" when an external
  822.  *        divider is available to generate the TX clock.    When the clock
  823.  *        source is PCLK, this can be a /32 divider between TRxC and RTxC.
  824.  *        When the clock is at RTxC, the TX rate must be supplied at TRxC.
  825.  *        This is needed only for AX.25 fullduplex.
  826.  *        When this arg is given as "ext", the transmit and receive clock
  827.  *        are external, and the BRG and DPLL are not used.
  828.  *        On the BayCom-USCC card "ext" enables NRZ-mode for DF9IC-modem.
  829.  * argv[6]: buffer size
  830.  */
  831. int
  832. scc_attach(int argc,char **argv,void *p)
  833. {
  834.     struct iface *ifp;
  835.     struct sccchan *scc;
  836.     unsigned int chan, brgrate;
  837.     int pclk = 0, hwtype = 0, hwparam = 0, xdev;
  838.     char *ifn;
  839.  
  840.     /* first handle the special "init" mode, to initialize global stuff */
  841.     if(!strcmp(argv[2],"init")) {
  842.         if(argc < 11) {                 /* need at least argv[1]..argv[10] */
  843.             return -1;
  844.         }
  845.         switch(tolower(*argv[10])) {
  846.         case 'p':
  847.             pclk = 1;
  848.         case 'r':
  849.             argv[10]++;
  850.         }
  851.         if(argc > 11) {                 /* optional hardware type */
  852.             hwtype = htoi(argv[11]);    /* it is given in hex */
  853.         }
  854.         if(argc > 12) {                 /* optional hardware param */
  855.             hwparam = htoi(argv[12]);   /* also in hex */
  856.         }
  857.         if(Sccinfo.init){
  858.             tputs("SCC driver already initialized - nothing done\n");
  859.             return 1;
  860.         }
  861.         return scc_init(
  862.             atoi(argv[1]),(ioaddr)htol(argv[3]),atoi(argv[4]),atoi(argv[5]),
  863.             atoi(argv[6]),atoi(argv[7]),(ioaddr)htol(argv[8]),atoi(argv[9]),
  864.             atol(argv[10]),pclk,hwtype,hwparam);
  865.     }
  866.     /* not "init", so it must be a valid mode to attach a channel */
  867.     if(!*Mycall) {
  868.         tputs("Mycall not set\n");
  869.         return -1;
  870.     }
  871.     if(!Sccinfo.init){
  872.         tputs("First init SCC driver\n");
  873.         return -1;
  874.     }
  875.     if((chan = atoi(argv[1])) > Sccinfo.maxchan){
  876.         tprintf("SCC channel %d out of range\n",chan);
  877.         return -1;
  878.     }
  879.     if(Sccchan[chan] != NULLCHAN){
  880.         tprintf("SCC channel %d already attached\n",chan);
  881.         return -1;
  882.     }
  883.     /* create interface structure and fill in details */
  884.     ifp = (struct iface *) mxallocw(sizeof(struct iface));
  885.     ifp->addr = Ip_addr;
  886.     ifp->hwaddr = strxdup(Mycall);
  887.     ifp->dev = chan;
  888.     ifp->mtu = atoi(argv[4]);
  889.     ifp->name = strxdup(argv[3]);
  890.     ifp->stop = scc_stop;
  891.  
  892.     ifn = if_name(ifp," rx");
  893.  
  894.     scc = (struct sccchan *)mxallocw(sizeof(struct sccchan));
  895.     Sccchan[chan] = scc;        /* put addr in table for interrupts */
  896.  
  897.     scc->iface = ifp;
  898.     scc->ctrl = Sccinfo.iobase + (chan / 2) * Sccinfo.space + Sccinfo.off[chan % 2];
  899.     scc->data = scc->ctrl + Sccinfo.doff;
  900.  
  901.     switch(tolower(*argv[5])) {
  902.     case 'd':                   /* fulldup divider installed? */
  903.         scc->fulldup = 1;        /* set appropriate flag */
  904.         argv[5]++;              /* skip the 'd' */
  905.         break;
  906.     case 'e':                   /* external clocking? */
  907.         scc->extclock = 1;        /* set the flag */
  908.         argv[5]++;
  909.         break;
  910.     }
  911.     scc->bufsiz = atoi(argv[6]);
  912.  
  913.     switch(tolower(*argv[2])) {                   /* mode already checked above */
  914. #ifdef AX25
  915.     case 'a':                                   /* AX.25 */
  916.         scc_sdlc(scc);                          /* init SCC in SDLC mode */
  917.  
  918.         if(!scc->extclock) {
  919.             brgrate = scc_speed(scc,32,atol(argv[5]));          /* init SCC speed */
  920.             scc->speed = Sccinfo.clk / (64L * (brgrate + 2));   /* calc real speed */
  921.         }
  922.         brgrate = scc_speed(scc,32,atol(argv[5]));/* init SCC speed */
  923.         scc->speed = Sccinfo.clk / (64L * (brgrate + 2));/* calc real speed */
  924.  
  925.         setencap(ifp,"AX25");
  926.  
  927.         ifp->ioctl = scc_sioctl;
  928.         ifp->raw = scc_raw;
  929.  
  930.         /* default KISS Params */
  931.         scc->a.txdelay  = 25 * TPS/100;     /* 250 ms */
  932.         scc->a.persist  = 64;               /* 25% persistence */
  933.         scc->a.slottime = 10 * TPS/100;     /* 100 ms */
  934. #if TPS > 67
  935.         scc->a.tailtime = 3 * TPS/100;      /* 30 ms */
  936. #else
  937.         scc->a.tailtime = 2;                /* minimal reasonable value */
  938. #endif
  939.         scc->a.fulldup  = 0;                /* CSMA */
  940.         scc->a.waittime = 10 * TPS/100;     /* 100 ms */
  941.         scc->a.maxkeyup = 7;                /* 7 s */
  942.         scc->a.mintime  = 1;                /* 1 s */
  943.         scc->a.idletime = 120;              /* 120 s */
  944.         break;
  945.     case 'k':                               /* kiss */
  946.         scc_async(scc);                     /* init SCC in async mode */
  947.         brgrate = scc_speed(scc,16,atol(argv[5]));
  948.         scc->speed = Sccinfo.clk / (32L * (brgrate + 2));
  949.  
  950.         setencap(ifp,"AX25");
  951.  
  952.         ifp->ioctl = kiss_ioctl;
  953.         ifp->raw = kiss_raw;
  954.  
  955.         for(xdev = 0; xdev < SLIP_MAX; xdev++) {
  956.             if(Slip[xdev].iface == NULLIF) {
  957.                 break;
  958.             }
  959.         }
  960.         if(xdev >= SLIP_MAX) {
  961.             tprintf("Max %d KISS devices\n",SLIP_MAX);
  962.             goto quit;
  963.         }
  964.         Slip[xdev].iface = ifp;
  965.         Slip[xdev].type = CL_KISS;
  966.         Slip[xdev].send = scc_send;
  967.         Slip[xdev].get = get_scc;
  968.         
  969.         ifp->proc = newproc(ifn,256,asy_rx,xdev,NULL,NULL,0);
  970.         break;
  971. #endif
  972. #ifdef SLIP
  973.     case 's':                               /* slip */
  974.         scc_async(scc);                     /* init SCC in async mode */
  975.         brgrate = scc_speed(scc,16,atol(argv[5]));
  976.         scc->speed = Sccinfo.clk / (32L * (brgrate + 2));
  977.         
  978.         setencap(ifp,"SLIP");
  979.  
  980.         ifp->ioctl = scc_aioctl;
  981.         ifp->raw = slip_raw;
  982.         
  983.         for(xdev = 0; xdev < SLIP_MAX; xdev++) {
  984.             if(Slip[xdev].iface == NULLIF) {
  985.                 break;
  986.             }
  987.         }
  988.         if(xdev >= SLIP_MAX) {
  989.             tprintf("Max %d SLIP devices\n",SLIP_MAX);
  990.             goto quit;          
  991.         }
  992.         Slip[xdev].iface = ifp;
  993.         Slip[xdev].type = CL_SERIAL_LINE;
  994.         Slip[xdev].send = scc_send;
  995.         Slip[xdev].get = get_scc;
  996.         
  997.         ifp->proc = newproc(ifn,256,asy_rx,xdev,NULL,NULL,0);
  998.         break;
  999. #endif
  1000. #ifdef NRS
  1001.     case 'n':                               /* nrs */
  1002.         scc_async(scc);                     /* init SCC in async mode */
  1003.         brgrate = scc_speed(scc,16,atol(argv[5]));
  1004.         scc->speed = Sccinfo.clk / (32L * (brgrate + 2));
  1005.         
  1006.         setencap(ifp,"AX25");
  1007.  
  1008.         ifp->ioctl = scc_aioctl;
  1009.         ifp->raw = nrs_raw;
  1010.  
  1011.         for(xdev = 0; xdev < NRS_MAX; xdev++) {
  1012.             if(Nrs[xdev].iface == NULLIF) {
  1013.                 break;
  1014.             }
  1015.         }
  1016.         if(xdev >= NRS_MAX) {
  1017.             tprintf("Max %d NRS devices\n",NRS_MAX);
  1018.             goto quit;          
  1019.         }
  1020.         Nrs[xdev].iface = ifp;
  1021.         Nrs[xdev].type = CL_NONE;
  1022.         Nrs[xdev].send = scc_send;
  1023.         Nrs[xdev].get = get_scc;
  1024.  
  1025.         ifp->rxproc = newproc(ifn,256,nrs_recv,xdev,NULL,NULL,0);
  1026.         break;
  1027. #endif
  1028.     default:
  1029. quit:    
  1030.         tprintf("Mode %s unknown for SCC iface\n",argv[2]);
  1031.         xfree(ifn);
  1032.         xfree(ifp->name);
  1033.         xfree(ifp->hwaddr);
  1034.         xfree(ifp);
  1035.         xfree(scc);
  1036.         Sccchan[chan] = NULLCHAN;
  1037.         return -1;
  1038.     }
  1039.     ifp->xdev = xdev;
  1040.     ifp->niface = Niface++;
  1041.     ifp->next = Ifaces;         /* link interface in list */
  1042.     Ifaces = ifp;
  1043.     return 0;
  1044. }
  1045.  
  1046. /* de-activate SCC channel */
  1047. static int
  1048. scc_stop(struct iface *ifp,int tmp)
  1049. {
  1050.     struct sccchan *scc = Sccchan[ifp->dev];
  1051.  
  1052.     DISABLE();
  1053.  
  1054.     VOID(RDREG(scc->ctrl));                     /* make sure pointer is written */
  1055.     wr(scc,R9,(ifp->dev % 2) ? CHRB : CHRA);    /* reset the channel */
  1056.  
  1057.     switch(ifp->iftype->type) {
  1058.     case CL_SERIAL_LINE:
  1059.     case CL_KISS:
  1060.         xfree(scc->fifo.buf);
  1061.         break;
  1062.     }
  1063.     xfree(scc);
  1064.     Sccchan[ifp->dev] = NULLCHAN;
  1065.     RESTORE();
  1066.     
  1067.     return 0;
  1068. }
  1069.  
  1070. /* de-activate SCC driver on program exit */
  1071. void
  1072. sccstop(void)
  1073. {
  1074.     if(Sccinfo.init) {                  /* was it initialized? */
  1075.         maskoff(Sccinfo.ivec);          /* disable the interrupt */
  1076.         setirq(Sccinfo.ivec,Orgivec);    /* restore original interrupt vector */
  1077.     }
  1078. }
  1079.  
  1080. /*----------------------------------------------------------------------*
  1081. * sccreact, reactivate scc after a temporary suspend, i.e swapping      *
  1082. * nos onto something not addressable (XMS,EMS,FILE)                     *
  1083. *  7-feb-1992   AA6HM/DK5DC      first shot                             *
  1084. * 13-feb-1992   AA6HM/DK5DC      added the istate = dirps() stuff       *
  1085. *-----------------------------------------------------------------------*/
  1086.  
  1087. void
  1088. sccreact()
  1089. {
  1090. int i_state = dirps();
  1091.  
  1092.    if(Sccinfo.init)   {
  1093.       if (Sccvecloc){                   /* INTACK method selected?      */
  1094.          /* set interrupt vector to INTACK-generating routine  */
  1095.          setirq(Sccinfo.ivec,sccvec);
  1096.       } else {
  1097.          /* set interrupt vector to polling routine */
  1098.          setirq(Sccinfo.ivec,sccnovec);
  1099.       }
  1100.       maskon(Sccinfo.ivec);
  1101.    }
  1102.    restore(i_state);
  1103. }
  1104.  
  1105.  
  1106. /* perform ioctl on SCC (async) channel
  1107.  * this is used for SLIP mode only, and will read/set the line speed
  1108.  */
  1109. static int32
  1110. scc_aioctl(struct iface *ifp,int cmd,int set,int32 val)
  1111. {
  1112.     if(cmd == PARAM_SPEED) {
  1113.         struct sccchan *scc = Sccchan[ifp->dev];
  1114.  
  1115.         if(set) {
  1116.             unsigned int brgrate = scc_speed(scc,16,val);
  1117.             scc->speed = Sccinfo.clk / (32L * (brgrate + 2));
  1118.         }
  1119.         return scc->speed;
  1120.     }
  1121.     return 0;
  1122. }
  1123.  
  1124. /* perform ioctl on SCC (sdlc) channel
  1125.  * this is used for AX.25 mode only, and will set the "kiss" parameters
  1126.  */
  1127. static int32
  1128. scc_sioctl(struct iface *ifp,int cmd,int set,int32 val)
  1129. {
  1130.     struct sccchan *scc = Sccchan[ifp->dev];
  1131.  
  1132.     switch(cmd) {
  1133.     case PARAM_SPEED:
  1134.         if(set) {
  1135.             if(val == 0) {
  1136.                 scc->extclock = 1;
  1137.             } else {
  1138.                 unsigned int brgrate = scc_speed(scc,32,val);/* init SCC speed */
  1139.                 scc->speed = Sccinfo.clk / (64L * (brgrate + 2));/* calc real speed */
  1140.             }
  1141.         }
  1142.         return scc->speed;
  1143.     case PARAM_TXDELAY:
  1144.         if(set) {
  1145.             scc->a.txdelay = val;
  1146.         }
  1147.         return scc->a.txdelay;
  1148.     case PARAM_PERSIST:
  1149.         if(set) {
  1150.             scc->a.persist = val;
  1151.         }
  1152.         return scc->a.persist;
  1153.     case PARAM_SLOTTIME:
  1154.         if(set) {
  1155.             if((scc->a.slottime = val) == 0) {
  1156.                 scc->a.slottime = 1;
  1157.             }
  1158.         }
  1159.         return scc->a.slottime;
  1160.     case PARAM_TXTAIL:
  1161.         if(set) {
  1162.             scc->a.tailtime = val;
  1163.         }
  1164.         return scc->a.tailtime;
  1165.     case PARAM_FULLDUP:
  1166.         if(set) {
  1167.             scc->a.fulldup = val;
  1168.         }
  1169.         return scc->a.fulldup;
  1170.     case PARAM_WAIT:
  1171.         if(set) {
  1172.             scc->a.waittime = val;
  1173.         }
  1174.         return scc->a.waittime;
  1175.     case PARAM_MAXKEY:
  1176.         if(set) {
  1177.             scc->a.maxkeyup = val;
  1178.         }
  1179.         return scc->a.maxkeyup;
  1180.     case PARAM_MIN:
  1181.         if(set) {
  1182.             scc->a.mintime = val;
  1183.         }
  1184.         return scc->a.mintime;
  1185.     case PARAM_IDLE:
  1186.         if(set) {
  1187.             scc->a.idletime = val;
  1188.         }
  1189.         return scc->a.idletime;
  1190.     case PARAM_DTR:
  1191.         if(set) {
  1192.             if(val) {
  1193.                 scc->wreg[R5] |= DTR;
  1194.             } else {
  1195.                 scc->wreg[R5] &= ~DTR;
  1196.             }
  1197.             DISABLE();
  1198.             if(scc->a.tstate == IDLE && scc->timercount == 0) {
  1199.                 scc->timercount = 1;    /* force an update */
  1200.             }
  1201.             RESTORE();
  1202.         }
  1203.         return (scc->wreg[R5] & DTR) ? 1 : 0;
  1204.     case PARAM_GROUP:
  1205.         if(set) {
  1206.             scc->group = (int)val;
  1207.         }
  1208.         return scc->group;
  1209.     }
  1210.     return -1;
  1211. }
  1212.  
  1213. /* show SCC status */
  1214. int
  1215. dosccstat(void)
  1216. {
  1217.     int i;
  1218.  
  1219.     if(!Sccinfo.init){
  1220.         tputs("SCC driver not initialized\n");
  1221.         return 0;
  1222.     }
  1223.     tputs("Ch Iface    Sent   Rcvd   Error Space Overr   Rxints   Txints   Exints   Spints\n");
  1224.  
  1225.     for(i = 0; i <= Sccinfo.maxchan; i++) {
  1226.         struct sccchan *scc;
  1227.         
  1228.         if((scc = Sccchan[i]) == NULLCHAN) {
  1229.             continue;
  1230.         }
  1231.         tprintf("%2d %-6s ",i,scc->iface->name);
  1232.         
  1233.         if(scc->int_receive == scc_asyrx) {
  1234.             tputs(" ** asynch **");
  1235.         } else {
  1236.             tprintf("%6lu %6lu",scc->enqueued,scc->rxframes);
  1237.         }    
  1238.         tprintf(" %7lu %5u %5u %8lu %8lu %8lu %8lu\n",
  1239.             scc->rxerrs,scc->nospace,scc->rovers,
  1240.             scc->rxints,scc->txints,scc->exints,scc->spints);
  1241.     }
  1242.     return 0;
  1243. }
  1244.  
  1245. /* send raw frame to SCC. used for AX.25 */
  1246. static int
  1247. scc_raw(struct iface *ifp,struct mbuf *bp)
  1248. {
  1249.     struct sccchan *scc = Sccchan[ifp->dev];
  1250.  
  1251.     dump(ifp,IF_TRACE_OUT,CL_AX25,bp);
  1252.  
  1253.     if(scc->tx_inhibit) {           /* transmitter inhibit */
  1254.         free_p(bp);
  1255.         return -1;
  1256.     }
  1257.     enqueue(&scc->sndq,bp);         /* enqueue packet */
  1258.     scc->enqueued++;
  1259.                                   
  1260.     DISABLE();
  1261.  
  1262.     if(scc->a.tstate == IDLE) {     /* when transmitter is idle */
  1263.         scc->a.tstate = DEFER;      /* start the key-up sequence */
  1264.         scc->a.maxdefer = TPS * scc->a.idletime / scc->a.slottime;
  1265.         scc->timercount = scc->a.waittime;
  1266.     }
  1267.     RESTORE();
  1268.     return 0;
  1269. }
  1270.  
  1271. static int 
  1272. scc_send(int dev,struct mbuf *bp)
  1273. {
  1274.     struct sccchan *scc = Sccchan[dev];
  1275.     
  1276.     enqueue(&scc->sndq,bp);
  1277.  
  1278.     if(scc->tbp == NULLBUF || scc->sndq != NULLBUF) {
  1279.         scc->tbp = dequeue(&scc->sndq);
  1280.         WRREG(scc->data,FR_END);
  1281.     }
  1282.     return 0;
  1283. }
  1284.  
  1285. /* SCC timer interrupt handler. 
  1286.  * Will be called every 1/TPS s by the routine systick in pc.c */ 
  1287. void 
  1288. scctimer(void) 
  1289.     struct sccchan *scc, **sccp;
  1290.  
  1291.     DISABLE();
  1292.     
  1293.     for(sccp = Sccchan + Sccinfo.maxchan; sccp >= Sccchan; sccp--) { 
  1294.         if((scc = *sccp) != NULLCHAN 
  1295.           && scc->timercount != 0 
  1296.           && --(scc->timercount) == 0) { 
  1297.             /* handle an SCC timer event for this SCC channel 
  1298.              * this can only happen when the channel is AX.25 type 
  1299.              * (the SLIP/KISS driver does not use timers) */ 
  1300.             switch(scc->a.tstate) { 
  1301.             case IDLE:                              
  1302.                 /* it was idle, this is FULLDUP2 timeout */ 
  1303.                 scc_txoff(scc);                     /* switch-off the transmitter */ 
  1304.                 break; 
  1305.             case DEFER:                             /* trying to get the channel */ 
  1306.                 /* operation is as follows: 
  1307.                  * CSMA: when channel clear AND persistence randomgenerator 
  1308.                  *   wins, AND group restrictions allow it: 
  1309.                  *      keyup the transmitter 
  1310.                  *   if not, delay one SLOTTIME and try again 
  1311.                  * FULL: always keyup the transmitter */ 
  1312.                  if(scc->a.fulldup == 0) { 
  1313.                     Random = 21 * Random + 53; 
  1314.                     if(scc->status & DCD || scc->a.persist < Random) { 
  1315.                         /* defer transmission again. check for limit */ 
  1316. defer_it:               if(--(scc->a.maxdefer) == 0) { 
  1317.                             /* deferred too long. choice is to: 
  1318.                              * - throw away pending frames, or 
  1319.                              * - smash-on the transmitter and send them. 
  1320.                              * the first would be the choice in a clean 
  1321.                              * environment, but in the amateur radio world 
  1322.                              * a distant faulty station could tie us up 
  1323.                              * forever, so the second may be better... */ 
  1324. #ifdef THROW_AWAY_AFTER_DEFER_TIMEOUT 
  1325.                             struct mbuf *bp,*bp1;
  1326.  
  1327.                             while ((bp = scc->sndq) != NULLBUF) { 
  1328.                                 scc->sndq = scc->sndq->anext; 
  1329.                                 free_p(bp); 
  1330.                             } 
  1331. #else 
  1332.                             goto keyup;             /* just keyup the transmitter... */ 
  1333. #endif 
  1334.                         } 
  1335.                         scc->timercount = scc->a.slottime; 
  1336.                         break; 
  1337.                     } 
  1338.                     if(uchar(scc->group) != NOGROUP) { 
  1339.                         int i; 
  1340.                         struct sccchan *scc2;
  1341.  
  1342.                         for(i = 0; i <= Sccinfo.maxchan; i++) { 
  1343.                             if((scc2 = Sccchan[i]) != NULLCHAN 
  1344.                               && scc2 != scc 
  1345.                               && uchar(scc2->group) & uchar(scc->group) 
  1346.                               && ((scc->group & TXGROUP && scc2->wreg[R5] & RTS) 
  1347.                               || (scc->group & RXGROUP && scc2->status & DCD))) { 
  1348.                                 goto defer_it; 
  1349.                             } 
  1350.                         } 
  1351.                     } 
  1352.                 } 
  1353.             case KEYUP:                                         /*  keyup transmitter (note fallthrough) */ 
  1354. keyup:          if((scc->wreg[R5] & RTS) == 0) {                /* when not yet keyed */ 
  1355.                     scc->a.tstate = KEYWT; 
  1356.                     scc->timercount = scc->a.txdelay;           /* 0 if CTSwait */ 
  1357.                     
  1358.                     /* Switch the SCC to "transmit" mode */ 
  1359.                     if(!scc->fulldup && !scc->extclock) {       /* no fulldup divider? */ 
  1360.                         cl(scc,R3,RxENABLE);                    /* then switch off receiver */ 
  1361.                         cl(scc,R5,TxENAB);                      /* transmitter off during switch */ 
  1362.                         scc_speed(scc,1,scc->speed);            /* reprogram baudrate generator */ 
  1363.                         /* DPLL -> Rx clk, BRG -> Tx CLK, TxCLK -> TRxC pin */ 
  1364.                         wr(scc,R11,RCDPLL|TCBR|TRxCOI|TRxCBR); 
  1365.                     } 
  1366.                     or(scc,R5,RTS|TxENAB);                      /* set the RTS line and enable TX */ 
  1367.                     
  1368.                     if(Sccinfo.hwtype & HWPRIMUS) {             /* PRIMUS has another PTT bit... */ 
  1369.                         WRREG(scc->ctrl + 4,Sccinfo.hwparam | 0x80); /* set that bit! */ 
  1370.                     }
  1371.                     break; 
  1372.                 } 
  1373.                 /* when already keyed, directly fall through */ 
  1374.             case KEYWT:                             /* waited for CTS or TXDELAY */ 
  1375.                 /* when a frame is available (it should be...): 
  1376.                  * - dequeue it from the send queue 
  1377.                  * - reset the transmitter CRC generator 
  1378.                  * - set a timeout on transmission length, if defined 
  1379.                  * - send the first byte of the frame 
  1380.                  * - reset the EOM latch 
  1381.                  * when no frame available, proceed to TAIL handling */ 
  1382.                 if((scc->tbp = scc->sndq) != NULLBUF) { 
  1383.                     scc->sndq = scc->sndq->anext; 
  1384.                     WRREG(scc->ctrl,RES_Tx_CRC); 
  1385.                     scc->a.tstate = ACTIVE; 
  1386.                     scc->timercount = TPS * scc->a.maxkeyup; 
  1387.                     scc_sdlctx(scc); 
  1388.                     WRREG(scc->ctrl,RES_EOM_L); 
  1389.                     break; 
  1390.                 } 
  1391.                 /* when  no frame queued, fall through to TAIL case */ 
  1392.             case TAIL:                              /* at end of frame */ 
  1393.                 /* when fulldup is 0 or 1, switch off the transmitter. 
  1394.                  * when frames are still queued (because of transmit time limit), 
  1395.                  * restart the procedure to get the channel after MINTIME. 
  1396.                  * when fulldup is 2, the transmitter remains keyed and we 
  1397.                  * continue sending. IDLETIME is an idle timeout in this case. */ 
  1398.                 if(scc->a.fulldup < 2) { 
  1399.                     scc->a.tstate = IDLE; 
  1400.                     scc_txoff(scc);
  1401.  
  1402.                     if(scc->sndq != NULLBUF) { 
  1403.                         scc->a.tstate = DEFER; 
  1404.                         scc->a.maxdefer = TPS * scc->a.idletime / scc->a.slottime; 
  1405.                         scc->timercount = TPS * scc->a.mintime; 
  1406.                     } 
  1407.                     break; 
  1408.                 } 
  1409.                 if(scc->sndq != NULLBUF) {          /* still frames on the queue? */ 
  1410.                     scc->a.tstate = KEYWT;          /* continue sending */ 
  1411.                     scc->timercount = TPS * scc->a.mintime;     /* after mintime */ 
  1412.                 } else { 
  1413.                     scc->a.tstate = IDLE; 
  1414.                     scc->timercount = TPS * scc->a.idletime; 
  1415.                 } 
  1416.                 break; 
  1417.             case ACTIVE:                            /* max keyup time expired */ 
  1418.             case FLUSH:                             /* same while in flush mode */ 
  1419.                 break;                              /* no action required yet */ 
  1420.             default:                                /* unexpected state */ 
  1421.                 scc->a.tstate = IDLE;               /* that should not happen, but... */ 
  1422.                 scc_txoff(scc);                     /* at least stop the transmitter */ 
  1423.                 break; 
  1424.             } 
  1425.         } 
  1426.     } 
  1427.     RESTORE(); 
  1428. }
  1429.  
  1430. #endif
  1431.